﻿//===================================================
// Rifetune Framework | www.rifetune.com            |
// --------------------------------------------------
// Copyright © 江苏瑞蚨通软件科技有限公司 2011      |
// All rights reserved.                             |
//===================================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace TetrisGame
{
    public partial class Form1 : Form
    {
        #region 【常数】
        private const int MAX_MAP_X = 14;
        private const int MAX_MAP_Y = 25;

        private const int CELL_SIZE = 10;

        private const int BLOCK_VALUE = 1;
        private const int WALL_VALUE = 2;
        #endregion

        #region 【字段】
        private Timer timer = new Timer();
        private int score = 0;

        private int moving_x = 0;
        private int moving_y = 0;

        private int moving_shape = 0;
        private int moving_rotate = 0;

        private int[,] map = new int[MAX_MAP_X, MAX_MAP_Y];

        private int[][][] shapes = new int[][][] {            
            new int[][]{ // I形
                new int[]{0,1,0,0, 0,1,0,0, 0,1,0,0, 0,1,0,0},
                new int[]{0,0,0,0, 1,1,1,1, 0,0,0,0, 0,0,0,0},
                new int[]{0,1,0,0, 0,1,0,0, 0,1,0,0, 0,1,0,0},
                new int[]{0,0,0,0, 1,1,1,1, 0,0,0,0, 0,0,0,0}
            },
            new int[][]{ // Z形
                new int[]{1,1,0,0, 0,1,1,0, 0,0,0,0, 0,0,0,0},
                new int[]{0,1,0,0, 1,1,0,0, 1,0,0,0, 0,0,0,0},
                new int[]{1,1,0,0, 0,1,1,0, 0,0,0,0, 0,0,0,0},
                new int[]{0,1,0,0, 1,1,0,0, 1,0,0,0, 0,0,0,0}
            },
            new int[][]{ // S形
                new int[]{0,1,1,0, 1,1,0,0, 0,0,0,0, 0,0,0,0},
                new int[]{1,0,0,0, 1,1,0,0, 0,1,0,0, 0,0,0,0},
                new int[]{0,1,1,0, 1,1,0,0, 0,0,0,0, 0,0,0,0},
                new int[]{1,0,0,0, 1,1,0,0, 0,1,0,0, 0,0,0,0}
            },
            new int[][]{ // 丄形
                new int[]{1,0,0,0, 1,1,0,0, 1,0,0,0, 0,0,0,0},
                new int[]{1,1,1,0, 0,1,0,0, 0,0,0,0, 0,0,0,0},
                new int[]{0,1,0,0, 1,1,0,0, 0,1,0,0, 0,0,0,0},
                new int[]{0,1,0,0, 1,1,1,0, 0,0,0,0, 0,0,0,0}
            },
            new int[][]{ // L形
                new int[]{1,0,0,0, 1,0,0,0, 1,1,0,0, 0,0,0,0},
                new int[]{1,1,1,0, 1,0,0,0, 0,0,0,0, 0,0,0,0},
                new int[]{1,1,0,0, 0,1,0,0, 0,1,0,0, 0,0,0,0},
                new int[]{0,0,1,0, 1,1,1,0, 0,0,0,0, 0,0,0,0}
            },
            new int[][]{ // 田形
                new int[]{1,1,0,0, 1,1,0,0, 0,0,0,0, 0,0,0,0},
                new int[]{1,1,0,0, 1,1,0,0, 0,0,0,0, 0,0,0,0},
                new int[]{1,1,0,0, 1,1,0,0, 0,0,0,0, 0,0,0,0},
                new int[]{1,1,0,0, 1,1,0,0, 0,0,0,0, 0,0,0,0}
            }
        };
        #endregion

        #region 【构造方法】
        /// <summary>
        /// 实例化一个窗体。
        /// </summary>
        public Form1()
        {
            InitializeComponent();

            this.StartGame();//开始游戏。

            timer.Interval = 1000;
            timer.Tick += new EventHandler(timer_Tick);
        }

        #region 【 Timer 事件】
        /// <summary>
        /// 计时器启用事件。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void timer_Tick(object sender, EventArgs e)
        {
            this.Invalidate();
            if (ValidateMovingBlock(moving_rotate, moving_x, moving_y + 1))
            {
                moving_y += 1;
            }
            else
            {
                this.AddMovingBlockToMap();
                this.CreateMovingBlock();
                this.DeleteAllFullRow();
            }
        }

        /// <summary>
        /// 消除满行
        /// </summary>
        private void DeleteAllFullRow()
        {
            for (int j = 0; j < MAX_MAP_Y; j++)
            {
                int count = 0;
                for (int i = 0; i < MAX_MAP_X; i++)
                {
                    if (map[i, j] == BLOCK_VALUE)
                    {
                        count++;
                    }
                }
                if (count == MAX_MAP_X - 2)
                {
                    this.DeleteFullRow(j);
                }
            }
        }

        /// <summary>
        /// 删除指定行。（分数加1分）
        /// </summary>
        /// <param name="j"></param>
        private void DeleteFullRow(int j)
        {
            for (; j >= 0; j--)
            {
                for (int i = 1; i < MAX_MAP_X - 1; i++)
                {
                    map[i, j] = j == 0 ? 0 : map[i, j - 1];
                }
            }
            this.score += 1;
        }
        #endregion

        #endregion

        #region 【游戏设置】
        /// <summary>
        /// 开始游戏。
        /// </summary>
        private void StartGame()
        {
            map = new int[MAX_MAP_X, MAX_MAP_Y];
            this.score = 0;
            this.SetWallToMap();
            this.CreateMovingBlock();

            timer.Start();
        }

        /// <summary>
        /// 设置 map 数组中墙面的初始值。
        /// </summary>
        private void SetWallToMap()
        {
            for (int i = 0; i < MAX_MAP_X; i++)
            {
                map[i, MAX_MAP_Y - 1] = WALL_VALUE;
            }
            for (int j = 0; j < MAX_MAP_Y; j++)
            {
                map[0, j] = 2;
                map[MAX_MAP_X - 1, j] = WALL_VALUE;
            }
        }
        #endregion

        #region 【活动方块相关方法】
        /// <summary>
        /// 将活动方块加入到 map 中。
        /// </summary>
        private void AddMovingBlockToMap()
        {
            for (int i = 0; i < 16; i++)
            {
                if (shapes[moving_shape][moving_rotate][i] == BLOCK_VALUE)
                {
                    int x = i % 4 + this.moving_x + 1;
                    int y = (int)i / 4 + this.moving_y;
                    map[x, y] = shapes[this.moving_shape][this.moving_rotate][i];
                }
            }
        }

        /// <summary>
        /// 新建活动方块。
        /// </summary>
        private void CreateMovingBlock()
        {
            Random random = new Random();
            this.moving_shape = random.Next(5);
            this.moving_rotate = 0;
            this.moving_x = 4;
            this.moving_y = 0;
            if (this.ValidateMovingBlock(this.moving_rotate, this.moving_x, this.moving_y) == false)
            {
                this.timer.Stop();
                MessageBox.Show("游戏结束！");
            }
        }

        /// <summary>
        /// 验证活动方块的位置是否合法。
        /// </summary>
        /// <param name="_moving_rotate"></param>
        /// <param name="_moving_x"></param>
        /// <param name="_moving_y"></param>
        /// <returns></returns>
        private bool ValidateMovingBlock(int _moving_rotate, int _moving_x, int _moving_y)
        {
            for (int i = 0; i < 16; i++)
            {
                int x = i % 4 + _moving_x + 1;
                int y = (int)i / 4 + _moving_y;
                if (shapes[this.moving_shape][_moving_rotate][i] == BLOCK_VALUE &&
                    (map[x, y] == BLOCK_VALUE || map[x, y] == WALL_VALUE))
                {
                    return false;
                }
            }
            return true;
        }
        #endregion

        #region 【 Paint 事件方法区域】
        /// <summary>
        /// 引发 Paint 事件。
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            Graphics g = e.Graphics;
            int area_x = 5;
            int area_y = 25;

            // 绘制游戏区域
            this.DrawGameArea(g, area_x, area_y);

            // 绘制 map
            this.DrawMap(g, area_x, area_y);

            // 绘制活动方块
            this.DrawMovingShape(g, area_x, area_y);

            g.DrawString("分数：" + this.score, Font, Brushes.Black, new PointF(MAX_MAP_X * CELL_SIZE + 10, area_y + 10f));
        }

        /// <summary>
        /// 绘制活动方块。
        /// </summary>
        /// <param name="g"></param>
        /// <param name="area_x"></param>
        /// <param name="area_y"></param>
        private void DrawMovingShape(Graphics g, int area_x, int area_y)
        {
            for (int i = 0; i < 16; i++)
            {
                if (shapes[moving_shape][moving_rotate][i] == BLOCK_VALUE)
                {
                    int x = i % 4 + moving_x + 1;
                    int y = (int)i / 4 + moving_y;
                    this.DrawBlockCell(g, x * CELL_SIZE + area_x, y * CELL_SIZE + area_y);
                }
            }
        }

        #region 【绘制 map】
        /// <summary>
        /// 绘制 map
        /// </summary>
        /// <param name="g"></param>
        /// <param name="area_x"></param>
        /// <param name="area_y"></param>
        private void DrawMap(Graphics g, int area_x, int area_y)
        {
            for (int i = 0; i < MAX_MAP_X; i++)
            {
                for (int j = 0; j < MAX_MAP_Y; j++)
                {
                    if (map[i, j] == BLOCK_VALUE)
                    {
                        this.DrawBlockCell(g, i * CELL_SIZE + area_x, j * CELL_SIZE + area_y);
                    }
                    if (map[i, j] == WALL_VALUE)
                    {
                        this.DrawWallCell(g, i * CELL_SIZE + area_x, j * CELL_SIZE + area_y);
                    }
                }
            }
        }

        /// <summary>
        /// 绘制方块 Cell。
        /// </summary>
        /// <param name="g"></param>
        /// <param name="area_x"></param>
        /// <param name="area_y"></param>
        private void DrawBlockCell(Graphics g, int x, int y)
        {
            Pen linePen = new Pen(Color.Black);
            Brush wallColor = Brushes.Black;
            g.FillRectangle(wallColor, new Rectangle(x + 3, y + 3, CELL_SIZE - 5, CELL_SIZE - 5));
            g.DrawRectangle(linePen, new Rectangle(x, y, CELL_SIZE, CELL_SIZE));
        }

        /// <summary>
        /// 绘制墙壁 Cell 。
        /// </summary>
        /// <param name="g"></param>
        /// <param name="area_x"></param>
        /// <param name="area_y"></param>
        private void DrawWallCell(Graphics g, int x, int y)
        {
            Pen linePen = new Pen(Color.Black);
            Brush wallColor = Brushes.Yellow;
            g.FillRectangle(wallColor, new Rectangle(x, y, CELL_SIZE, CELL_SIZE));
            g.DrawRectangle(linePen, new Rectangle(x, y, CELL_SIZE, CELL_SIZE));
        }
        #endregion

        /// <summary>
        /// 绘制游戏区域。
        /// </summary>
        /// <param name="g"></param>
        /// <param name="area_x"></param>
        /// <param name="area_y"></param>
        private void DrawGameArea(Graphics g, int area_x, int area_y)
        {
            Pen linePen = new Pen(Color.Black);
            g.FillRectangle(Brushes.White, new Rectangle(area_x, area_y, MAX_MAP_X * CELL_SIZE, MAX_MAP_Y * CELL_SIZE));
            g.DrawRectangle(linePen, new Rectangle(area_x, area_y, MAX_MAP_X * CELL_SIZE, MAX_MAP_Y * CELL_SIZE));
        }

        #endregion

        #region 【键盘方向控制】
        /// <summary>
        /// 引发 KeyDown 事件。
        /// </summary>
        /// <param name="e"></param>
        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);
            switch (e.KeyData)
            {
                case Keys.Left:
                    this.MoveToLeft();
                    break;
                case Keys.Right:
                    this.MoveToRight();
                    break;
                case Keys.Up:
                    this.RotateBlock();
                    break;
                case Keys.Down:
                    this.FastDown();
                    break;
            }
        }
        /// <summary>
        /// 向左移动方块。
        /// </summary>
        private void MoveToLeft()
        {
            if (moving_x > 0 && this.ValidateMovingBlock(this.moving_rotate, this.moving_x - 1, this.moving_y))
            {
                this.moving_x -= 1;
                this.Invalidate();
            }
        }
        /// <summary>
        /// 向右移动方块。
        /// </summary>
        private void MoveToRight()
        {
            if (moving_x < MAX_MAP_X - 2 && this.ValidateMovingBlock(this.moving_rotate, this.moving_x + 1, this.moving_y))
            {
                this.moving_x += 1;
                this.Invalidate();
            }
        }
        /// <summary>
        /// 点击向上键，旋转方块。
        /// </summary>
        private void RotateBlock()
        {
            if (this.ValidateMovingBlock((this.moving_rotate + 1) % 4, this.moving_x, this.moving_y))
            {
                this.moving_rotate = (this.moving_rotate + 1) % 4;
                this.Invalidate();
            }
        }
        /// <summary>
        /// 向下移动方块。
        /// </summary>
        private void FastDown()
        {
            if (this.ValidateMovingBlock(this.moving_rotate, this.moving_x, this.moving_y + 1))
            {
                this.moving_y += 1;
                this.Invalidate();
            }
        }
        #endregion

        private void tsmi_Start_Click(object sender, EventArgs e)
        {
        }
    }
}
